优雅的关闭连接

您所在的位置:网站首页 Tensions linger 翻译 优雅的关闭连接

优雅的关闭连接

2023-09-16 11:49| 来源: 网络整理| 查看: 265

优雅关闭:如果发送缓存中还有数据未发出则其发出去,并且收到所有数据的ACK之后,发送FIN包,开始关闭过程。TCP连接线关闭一个方向,此时另外一个方向还是可以正常进行数据传输。

强制关闭:如果缓存中还有数据,则这些数据都将被丢弃,然后发送RST包,直接重置TCP连接。两边都关闭了,服务端处理完的信息没有正常传给客户端。

 

一、使用shudown优雅的关闭连接 1.1、close()函数: #include int close(int fd);

close()函数会使套接字的引用计数减1,若套接字的引用计数为0,则彻底关闭连接,并且会关闭TCP两个方向的数据流,既不能发送数据也不能接收数据。close函数不能关闭一个方向上的连接,而shutdown函数可以实现。如果服务端还又没有处理完的数据,不能正常发送给客户端。

 

1.2、shutdown函数 int shutdown(int sock, int howto);

参数howto的取值:     SHUT_RD:断开输入流。套接字无法接收数据(即使输入缓冲区收到数据也被抹去),无法调用输入相关函数。     SHUT_WR:断开输出流。套接字无法发送数据,但如果输出缓冲区中还有未传输的数据,则将传递到目标主机。     SHUT_RDWR:同时断开 I/O 流。相当于分两次调用 shutdown(),其中一次以 SHUT_RD 为参数,另一次以 SHUT_WR 为参数。

 

1.3、close()和shutdown()的区别 close会关闭连接了,并释放所有连接对应的资源,而shutdown并不会释放掉套接字和所有资源。close有引用计数,例如父子进程都打开了某个文件描述符,其中某个进程调用了close函数,会使close函数的引用计数减1,直到套接字的引用计数为0,才会真正的关闭连接。而shutdown函数可以无视引用计数,直接关闭连接。close的引用计数的存在导致不一定会发出FIN结束报文,而shutdown一定会发出FIN报文。shutdown() 用来关闭连接,而不是套接字,不管调用多少次 shutdown(),套接字依然存在,直到调用 close() / closesocket() 将套接字从内存清除。调用 close()关闭套接字时,或调用 shutdown() 关闭输出流时,都会向对方发送 FIN 包。FIN 包表示数据传输完毕,计算机收到 FIN 包就知道不会再有数据传送过来。默认情况下,close()引用计数为0后会立即往网络中发送FIN包,不管输出缓冲区中是否还有数据,而shutdown() 会等输出缓冲区中的数据传输完毕再发送FIN包。也就意味着,调用 close()将丢失输出缓冲区中的数据,而调用 shutdown() 不会。

 

二、使用setsockopt设置SO_LINGER实现优雅的关闭连接 2.1 LINGER

LINGER结构包含了指定套接字的信息,当调用了close()函数关闭该套接字时,LINGER结构中的信息指定了如何处理未发送的数据。

typedef struct linger {  u_short l_onoff; u_short l_linger; } LINGER, *PLINGER, *LPLINGER;

参数:

l_onoff

l_linger

close行为

发送队列

底层行为

忽略

立即返回。

保持直至发送完成。

系统接管套接字并保证将数据发送至对端。(就是正常的close)

非零

立即返回。

立即放弃。

直接发送RST包,自身立即复位,不用经过2MSL状态。对端收到复位错误号。

非零

非零

阻塞直到l_linger时间超时或数据发送完成。(套接字必须设置为阻塞)

在超时时间段内保持尝试发送,若超时则立即放弃。

超时则同第二种情况,若发送完成则皆大欢喜。

取值方案:

设置 l_onoff为0,则该选项关闭,l_linger的值被忽略,等于内核缺省情况,close调用会立即返回给调用者,如果可能将会传输任何未发送的数据;设置 l_onoff为非0,l_linger为0,当调用close的时候,TCP连接会立即断开.send buffer中未被发送的数据将被丢弃,并向对方发送一个RST信息.值得注意的是,由于这种方式,不是以4次握手方式结束TCP链接,所以,TCP连接将不会进入TIME_WAIT状态,这样会导致新建立的可能和就连接的数据造成混乱。这种关闭方式称为“强制”或“失效”关闭。设置 l_onoff 为非0,l_linger为非0,在这种情况下,回事的close返回得到延迟。调用close去关闭socket的时候,内核将会延迟。也就是说,如果send buffer中还有数据尚未发送,该进程将会被休眠直到一下任何一种情况发生:

a. send buffer中的所有数据都被发送并且得到对方TCP的应答消息(这种应答并不是意味着对方应用程序已经接收到数据)

b.延迟时间消耗完。在延迟时间被消耗完之后,send buffer中的所有数据都将会被丢弃。

这种关闭称为“优雅的”关闭。

 

2.2 setsockopt

setsockopt()函数的作用是设置套接字的选项。

man手册查阅函数原型:

#include /* See NOTES */ #include int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

参数:

sockfd表示要设置选项的套接字;level指定了选项的级别,对于套接字优雅关闭的选项,该值设置为SOL_SOCKET;optname表示要设置套接字的选项,该选项必须是在level中定义的,如果设置套接字需要优雅关闭,则该参数的值为SO_LINGER,如果套接字直接关闭,则该参数的值为SO_DONTLINGER;optval是缓冲区的指针,该缓冲区中包含了选项的值;optlen是optval指向的缓冲区的大小。

返回值:

如果setsockopt()函数执行成功,则返回值是0,否则返回值为SOCKET_ERROR。

总结:

       通过setsockopt可以设置SO_LINGER,从而实现优雅的关闭连接

示例:

struct linger tmp = {1, 1}; setsockopt(sockfd, SOL_SOCKET, SO_LINGER, &tmp, sizeof(tmp));

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3